require("GameSetup.Map")
require("GameSetup.Audio")
require("GameSetup.Player")
require("Helpers.CaptureBuildings")
require("Helpers.InputHelper")
require("Helpers.Textures")
require("Helpers.Menu")
require("StartGame")
require("Helpers.FogHelper")
require("Helpers.BuildingHelper")
require("Helpers.ScreenActionHelper")
require("Helpers.AttackHelper")

function initVariables()
  typesOfScreens = {
    ["mainmenu"] = "mainmenu",
    ["chooselevel"] = "chooselevel",
    ["game"] = "game",
    ["guide"] = "guide"
  }
  
  player1IsFollowingTut = true
  player2IsFollowingTut = true
  
  tutRecruit1 = false
  tutRecruit2 = false
  
  tutTapIcon1 = false
  tutTapIcon2 = false
  
  tutTapMove1 = false
  tutTapMove2 = false
  
  tutEnd1 = false
  tutEnd2 = false
  
  foghelper = FogHelper.new()
  isFogOn = false
  
  currentScreen = typesOfScreens["mainmenu"]
  isGameLoopRunning = false

  --screenWidth = MOAIEnvironment.horizontalResolution
  --screenHeight = MOAIEnvironment.verticalResolution
  
  --screenWidth = MOAIEnvironment.screenWidth
  --screenHeight = MOAIEnvironment.screenHeight

  mainMenuPartition = MOAIPartition.new()
  chooseLevelPartition = MOAIPartition.new()
  guidePartition = MOAIPartition.new()
  gamePartition = MOAIPartition.new()

  renderLayerTable = {}
  unitHealthBoxRenderTable = {}
  captureRenderTable = {}
  
  MainLayer = nil
  viewport = nil
  input = InputHelper.new()
  camera = MOAICamera2D.new()
  camera:setLoc(0, 0)
  cameraLocPlayer1 = nil
  cameraLocPlayer2 = nil
  xCamP1 = nil
  yCamP1 = nil
  xCamP2 = nil
  yCamP2 = nil
  tempX1 = 0
  tempX2 = 0
  
  nightShadeList = {}
  allPropsTable = {}

  audio = Audio.new()
  audio:loadAudio()
  audioTurnedOn = true
  audio:startMenuAudio()
  captureBuilding = CaptureBuildings.new()
  startGame = StartGame.new()
  alreadyClicked = false
  settingsPropActive = false
  buildingHelper = BuildingHelper.new()
  screenActionHelper = ScreenActionHelper.new()
  attackHelper = AttackHelper.new()

  rangeTurnedOn = false
  rangeProps = {}
  userCanClick = true
  selectedUnit = nil
  chosenUnit = nil
  lastTile = nil
  selectedUnitRange = nil
  isVictoryScreen = false
  doneButtonShowed = false
  isUnitMoving = false
  guideScreen = 1
  
  attackProps = {}
  attackPossibilitiesOn = false
  
  usedUnits = {}
  
  chooseLevelLinks = {}
  mainMenuLinks = {}
  isProductionOverlayShowed = false
  charcodes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;'\"(!?)+-*/= "
  font = nil
  style = nil
  
  captureBuildingsList = {}

  propToTileObject = {}

  goldTurnTextbox = nil
  currentTurn = 1

  currentPlayerTurn = nil
  pl1 = nil
  pl2 = nil
end

function setupScreen()
  if screenWidth == nil then screenWidth = 800 end
  if screenHeight == nil then screenHeight = 640 end

  sizeMenuBalk = 50
  baseScreenWidth = 768                   -- map moet minimaal 12 kolommen breed
  baseScreenHeight =  640 + sizeMenuBalk  -- map moet minimaal 10 kolommen hoog
  
  MOAISim.openWindow("Game Design - Triumph", screenWidth, screenHeight)

  viewport = MOAIViewport.new()
  viewport:setSize(screenWidth, screenHeight)
  viewport:setScale(baseScreenWidth, baseScreenHeight)
  viewport:setOffset(-1, 1)
  
  MainLayer = MOAILayer2D.new()
  MainLayer:setViewport(viewport)
  MainLayer:setPartition(mainMenuPartition)
  MainLayer:setPriority(100)
  
  renderLayerTable[1] = MainLayer
  
  MOAIRenderMgr.setRenderTable(renderLayerTable)
  MainLayer:setCamera(camera)
end

function setupFonts()
  font = MOAIFont.new()
  font:load("resources/font/ebrima.TTF")
  font:preloadGlyphs(charcodes, 24)
  font:preloadGlyphs(charcodes, 20)
  
  style = MOAITextStyle.new()
  style:setFont(font)
  style:setSize(24)
  
  styleHealthCaptureBox = MOAITextStyle.new()
  styleHealthCaptureBox:setFont(font)
  styleHealthCaptureBox:setSize(20)
end

function startGameLoop()
  thread = MOAIThread.new()
  isGameLoopRunning = true
  thread:run(function()
      while isGameLoopRunning == true do
        update()
        coroutine.yield()
      end
    end
    )
end

function update()
  if currentScreen == typesOfScreens["game"] then
    playerTextbox:setString("Player: " .. currentPlayerTurn:getName())
    goldTextBox:setString("" .. currentPlayerTurn:getGold())
    turnTextbox:setString("Turn number: " .. currentTurn)
    
    for k, v in pairs(pl1:getOwnedUnitsList()) do
      v:updateHealthBox()
    end
    
    for k, v in pairs(pl2:getOwnedUnitsList()) do
      v:updateHealthBox()
    end
  end
end

function moveCamera(_x, _y, amount, direction)
  camera:moveLoc(_x, _y)
  
  if propOverlay ~= nil then
    propOverlay:moveLoc(_x, _y)
  end

  if direction ~= nil then
    local gx1, gy1, gx2, gy2 = getStaticLocationValue(direction, amount, goldTextBox)
    local px1, py1, px2, py2 = getStaticLocationValue(direction, amount, playerTextbox)
    local tx1, ty1, tx2, ty2 = getStaticLocationValue(direction, amount, turnTextbox)
  
    goldTextBox:setRect(gx2, gy2, gx1, gy1)
    playerTextbox:setRect(px2, py2, px1, py1)
    turnTextbox:setRect(tx2, ty2, tx1, ty1)
  end
end

function getStaticLocationValue(direction, amount, prop)
  local x1, y1, x2, y2 = prop:getRect()
  if direction == "left" then
    x1 = x1 + amount
    x2 = x2 + amount
  elseif direction  == "right" then
    x1 = x1 - amount
    x2 = x2 - amount
  elseif direction == "up" then
    y1 = y1 - amount
    y2 = y2 - amount
  elseif direction == "down" then
    y1 = y1 + amount
    y2 = y2 + amount   
  end
  
  return x1, y1, x2, y2
end

function setTexturePlayer(sprite, gg)
  if gg:getType() ~= "Grass" and gg:getType() ~= "Forrest1" and gg:getType() ~= "Forrest2" and gg:getType() ~= "Road_Horizontal" and gg:getType() ~= "Road_Vertical" and gg:getType()~= "Road_Loop1" and gg:getType()~= "Road_Loop2" and gg:getType()~= "Road_Loop3" and gg:getType()~= "Road_Loop4" and gg:getType()~= "Road_Split1" and gg:getType()~= "Road_Split2" and gg:getType()~= "Road_Split3" and gg:getType()~= "Road_Split4" and gg:getType()~= "Water1" and gg:getType()~= "Water2" and gg:getType()~= "Water3" and gg:getType()~= "Water4" and gg:getType()~= "Water5" and gg:getType()~= "Water6" and gg:getType()~= "Water7" and gg:getType()~= "Water8" and gg:getType()~= "Water9" and gg:getType()~= "Water10" and gg:getType()~= "Water11" and gg:getType()~= "Water12" and gg:getType()~= "Water13" and gg:getType()~= "Water" and gg:getType() ~= "Big_Rocks" then
    if gg:getOwner() == "playerOne" then      
      sprite:setTexture(gg:getTexturePlayerOne())
    elseif gg:getOwner() == "playerTwo" then
      sprite:setTexture(gg:getTexturePlayerTwo())
    elseif gg:getOwner() == "neutral" then
      sprite:setTexture(gg:getTextureNeutral())
   end
  else 
    sprite:setTexture(gg:getTexture())
  end
end

function captureBuildings(unit, buildingUniton, buildingProp)
  return captureBuilding:capture(unit, buildingUniton, buildingProp)
end

function endTurn()
  clearUsedUnits()
  rotateWorld()
  
  currentTurn = currentTurn + 1
  
  if followBlueProp ~= nil then MainLayer:removeProp(followBlueProp) end
  if followRedProp ~= nil then MainLayer:removeProp(followRedProp) end
  
  if currentTurn == 2 and chosenLevel == 1 then
    if tutRecruit2 == false then
      tutRecruit2 = true
      local image = MOAIGfxQuad2D.new()
      image:setTexture("resources/graphics/ingame_menu/tutorialblue1.png")
      image:setRect(270, -630, 570, -500)

      tutBlue1 = MOAIProp2D.new()
      tutBlue1:setDeck(image)
      tutBlue1:setPriority(1000)
      MainLayer:insertProp(tutBlue1)
    end    
  end
  
  attackPossibilitiesOn = false
  screenActionHelper:removeAttackRanges()
  
  if unitselectionProp ~= nil then
    MainLayer:removeProp(unitselectionProp)
    unitselectionProp = nil
  end
  
  if buildingSelectionProp ~= nil then
    MainLayer:removeProp(buildingSelectionProp)
    buildingSelectionProp = nil
  end
  
  if currentPlayerTurn == pl1 then
    currentPlayerTurn = pl2
    
    endTurnTextbox:setString(pl2:getName() .. " it's your turn!")
    endTurnTextbox:setVisible(true)
    
    local timer = MOAITimer.new()
    timer:setMode(MOAITimer.NORMAL)
    timer:setSpan(0.75)
    timer:setListener(MOAITimer.EVENT_TIMER_END_SPAN, function() switchTurnsTextbox() end)
    timer:start()
    
  elseif currentPlayerTurn == pl2 then
    currentPlayerTurn = pl1
    
    endTurnTextbox:setString(pl1:getName() .. " it's your turn!")
    endTurnTextbox:setVisible(true)
    
    local timer = MOAITimer.new()
    timer:setMode(MOAITimer.NORMAL)
    timer:setSpan(0.75)
    timer:setListener(MOAITimer.EVENT_TIMER_END_SPAN, function() switchTurnsTextbox() end)
    timer:start()
  end
    
  local gold = 0
  for k, v in pairs(currentPlayerTurn:getOwnedBuildingsList()) do
    local temp = v:getIncomePerTurn()
    gold = gold + temp
  end
  currentPlayerTurn:increaseGold(gold)
  
  for kk, vv in pairs(currentPlayerTurn:getOwnedUnitsList()) do
    vv:setHasMoved(false)
    vv:setHasAttacked(false)
  end
  
  if propOverlay ~= nil then
    isProductionOverlayShowed = false
    propOverlay:moveLoc(0,-80,1)
    MainLayer:removeProp(propOverlay)
  end

  for kkk, vvv in pairs(captureBuildingsList) do
    local unit = vvv[1]
    local buildingObject = vvv[2]
    local buildingProp = vvv[3]
  
    local result = captureBuildings(unit, buildingObject, buildingProp)
    if isFogOn == true then
      if currentPlayerTurn == pl1 and unit:getOwnerObject() ~= pl1 then
        buildingObject:getCaptureTextbox():setVisible(false)
      elseif currentPlayerTurn == pl2 and unit:getOwnerObject() ~= pl2 then
        buildingObject:getCaptureTextbox():setVisible(false)
      end
    end
    
    if result == true then
      table.remove(captureBuildingsList, kkk)
      buildingObject:removeCaptureTextbox()
    end
    if result == false then
      buildingObject:updateCaptureTextbox()
    end
  end
  
  if isFogOn == true then
    foghelper:hideFogForCurrentPlayer()
  end
  
  if foghelper:checkIfFogNeedShown() == true and isFogOn == false then
    foghelper:showAllFog()
    foghelper:hideFogForCurrentPlayer()
    isFogOn = true
    
    for k, v in pairs(pl1:getOwnedUnitsList()) do
      v:setAttackRange(1, false)
    end
    
    for k, v in pairs(pl2:getOwnedUnitsList()) do
      v:setAttackRange(1, false)
    end
    
  elseif foghelper:checkIfFogNeedShown() == false and isFogOn == true then
    foghelper:hideAllFog()
    isFogOn = false
  end
end

function clearUsedUnits()
  for i= 1,table.getn(usedUnits) do
    usedUnits[i]:setColor(1.0,1.0,1.0,1.0)
  end
end

function switchTurnsTextbox()
  endTurnTextbox:setVisible(false)
end

function turnNightOn(_tile)
  local nightShade = MOAIGfxQuad2D.new()
  nightShade:setTexture("resources/graphics/world/black.png")
  nightShade:setRect(x1, y2, x2, y1)

  local nightShadeProp = MOAIProp2D.new()
  nightShadeProp:setDeck(nightShade)
  nightShadeProp:setPriority(90)
  table.insert(nightShadeList, nightShadeProp)
  
  MainLayer:insertProp(nightShadeProp)
  nightShadeProp:setVisible(false)
  _tile:setFogObject(nightShadeProp)
end

function round(x)
  if x%2 ~= 0.5 then
    return math.floor(x+0.5)
  end
  return x-0.5
end

function rotateWorld()
  for i, v in pairs(allPropsTable) do
      v:moveRot(0, 180, 0)
  end
end

-- Code
initVariables()
loadTextures()
setupScreen()
setupFonts()
input:setupInput()
showMainMenu()